package com.gitee.wsl.prism4j.languages

import com.gitee.wsl.prism4j.GrammarUtils
import com.gitee.wsl.prism4j.GrammarUtils.extend
import com.gitee.wsl.prism4j.GrammarUtils.require
import com.gitee.wsl.prism4j.Prism4j
import com.gitee.wsl.prism4j.Prism4j.Companion.grammar
import com.gitee.wsl.prism4j.Prism4j.Companion.pattern
import com.gitee.wsl.prism4j.Prism4j.Companion.token
import com.gitee.wsl.prism4j.annotations.Extend
import com.gitee.wsl.prism4j.Prism4j.Pattern

@Suppress("unused")
@Extend("markup")
object Prism_markdown {
    fun create(prism4j: Prism4j): Prism4j.Grammar {
        val markdown = extend(
            require(prism4j, "markup"),
            "markdown"
        )

        val bold: Prism4j.Token? = token(
            "bold", pattern(
                Pattern.compile("(^|[^\\\\])(\\*\\*|__)(?:(?:\\r?\\n|\\r)(?!\\r?\\n|\\r)|.)+?\\2"),
                true,
                false,
                null,
                grammar("inside", token("punctuation", pattern(Pattern.compile("^\\*\\*|^__|\\*\\*$|__$"))))
            )
        )

        val italic: Prism4j.Token? = token(
            "italic", pattern(
                Pattern.compile("(^|[^\\\\])([*_])(?:(?:\\r?\\n|\\r)(?!\\r?\\n|\\r)|.)+?\\2"),
                true,
                false,
                null,
                grammar("inside", token("punctuation", pattern(Pattern.compile("^[*_]|[*_]$"))))
            )
        )

        val url: Prism4j.Token? = token(
            "url", pattern(
                Pattern.compile("!?\\[[^\\]]+\\](?:\\([^\\s)]+(?:[\\t ]+\"(?:\\\\.|[^\"\\\\])*\")?\\)| ?\\[[^\\]\\n]*\\])"),
                false,
                false,
                null,
                grammar(
                    "inside",
                    token("variable", pattern(Pattern.compile("(!?\\[)[^\\]]+(?=\\]$)"), true)),
                    token("string", pattern(Pattern.compile("\"(?:\\\\.|[^\"\\\\])*\"(?=\\)$)")))
                )
            )
        )

        GrammarUtils.insertBeforeToken(
            markdown, "prolog",
            token("blockquote", pattern(Pattern.compile("^>(?:[\\t ]*>)*", Pattern.MULTILINE))),
            token(
                "code",
                pattern(Pattern.compile("^(?: {4}|\\t).+", Pattern.MULTILINE), false, false, "keyword"),
                pattern(Pattern.compile("``.+?``|`[^`\\n]+`"), false, false, "keyword")
            ),
            token(
                "title",
                pattern(
                    Pattern.compile("\\w+.*(?:\\r?\\n|\\r)(?:==+|--+)"),
                    false,
                    false,
                    "important",
                    grammar("inside", token("punctuation", pattern(Pattern.compile("==+$|--+$"))))
                ),
                pattern(
                    Pattern.compile("(^\\s*)#+.+", Pattern.MULTILINE),
                    true,
                    false,
                    "important",
                    grammar("inside", token("punctuation", pattern(Pattern.compile("^#+|#+$"))))
                )
            ),
            token(
                "hr", pattern(
                    Pattern.compile("(^\\s*)([*-])(?:[\\t ]*\\2){2,}(?=\\s*$)", Pattern.MULTILINE),
                    true,
                    false,
                    "punctuation"
                )
            ),
            token(
                "list", pattern(
                    Pattern.compile("(^\\s*)(?:[*+-]|\\d+\\.)(?=[\\t ].)", Pattern.MULTILINE),
                    true,
                    false,
                    "punctuation"
                )
            ),
            token(
                "url-reference", pattern(
                    Pattern.compile("!?\\[[^\\]]+\\]:[\\t ]+(?:\\S+|<(?:\\\\.|[^>\\\\])+>)(?:[\\t ]+(?:\"(?:\\\\.|[^\"\\\\])*\"|'(?:\\\\.|[^'\\\\])*'|\\((?:\\\\.|[^)\\\\])*\\)))?"),
                    false,
                    false,
                    "url",
                    grammar(
                        "inside",
                        token("variable", pattern(Pattern.compile("^(!?\\[)[^\\]]+"), true)),
                        token(
                            "string",
                            pattern(Pattern.compile("(?:\"(?:\\\\.|[^\"\\\\])*\"|'(?:\\\\.|[^'\\\\])*'|\\((?:\\\\.|[^)\\\\])*\\))$"))
                        ),
                        token("punctuation", pattern(Pattern.compile("^[\\[\\]!:]|[<>]")))
                    )
                )
            ),
            bold!!,
            italic!!,
            url!!
        )

        add(GrammarUtils.findFirstInsideGrammar(bold), url, italic)
        add(GrammarUtils.findFirstInsideGrammar(italic), url, bold)

        return markdown
    }

    private fun add(grammar: Prism4j.Grammar?, first: Prism4j.Token, second: Prism4j.Token) {
        if (grammar != null) {
            grammar.tokens().add(first)
            grammar.tokens().add(second)
        }
    }
}
